這系列標題不是 Angular 2之 30天邁向神乎奇蹟之路嗎?怎麼才第二天標題就是 TypeScript(之後簡稱 TS)了呢?怎麼有種掛羊頭賣狗肉的感覺呢?XD 先前提到 Angular 2很重要的一環便是它採用 TS當作開發語言,如果 Angular是一個網頁前端的精靈,那 TS就是他的靈魂啦!
事實上雖然你也可以完全使用純 JavaScript(之後簡稱JS)來開發,因為 TS本身就完全相容 JS,但身為 Super版的 JS,大家都在用了(尤其老大哥微軟跟 Google),尚未成為神乎其技的我們,跟著強者的方法一起修道準沒錯。所以首先我們要先把 TS弄清楚,不管是語法、變數、函數、風格等等之類的,都要有所了解,這樣對於之後開發 Angular只會有益無害,更何況學習新的事情是多麼令人開心的事呢!
接著就來認識一下 TS是甚麼吧!
TS是為了解決 JS諸多的問題,例如資料型別(typing)、名稱空間(namescpace)以及零碎的眉眉角角,而且由於當初設計 JS的階段過於倉促,加上沒有先例可以參考(第一個同時兼具函數程式和物件導向程式的語言),總總原因讓大家對 JS不太滿意,於是就有很多改善 JS的語言誕生,它們都希望減輕 JS開發人員的負擔,改用一些結構良好或是更輕鬆的語言來開發應用程式(Script#、CoffeeScript),再透過各自的編譯器來產出 JS程式碼, TS也是其中一個。
接著就來快速入門吧!讓我們看看 TypeScript有那些特殊的地方。
嚴格說起來這不算是 TS特殊的東西,在 ES6中對於宣告變數得更明確規範。
const cannotChange = 9; // 只要改變這個常數,程式會出錯
let canChange = [{'a': '1'}, {'b': '2'}]; //在不改變宣告的資料型別的情況下,可以改變這個參數
var
雖然還是能用,但能不用盡量不要用,越明確的規範對程式幫助越好。
以往在 JS 宣告變數是不需要宣告型別的,var
就是萬能,物件可以變數字,字串可以變布林,在絕大多數的情況下,這樣變來變去其實不好,雖然說不用宣告型別很方便,但就算再細心還是有出錯的一天,所以 TS又強制規定要宣告型別了。
以下是所有型別範例:
//Number
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
//Stirng
let person: string = "Mike"; //可以用 ""
let age: number = 37;
let sentence: string = `Oh, ${person} is ${age} years old.`; //也可以用 `${}`
//上面等於 "Oh, " + person + " is " + age + " years old."
//Array
let list: number[] = [1, 2, 3];
//Tuple
let x: [string, number]; // Array中包含不同型別的變數用 Tuple
x = ["hello", 10]; // OK
x = [10, "hello"]; // Error
x[3] = true // Error 往後的變數只能是一開始設定的 string 或 number
以往在 JS中函數的參數是不需要宣告參數的型別。
function greeter(person) {
return "Hello, " + person;
}
但是這樣沒人知道 person
是甚麼,到底是物件還是字串?
function greeter(person: string) {
return "Hello, " + person;
}
所以 TS強制要求參數要註釋型別 person: string
這樣一看就知道是字串,當專案越做越大,函數呼叫函數又在呼叫下個函數,參數滿天飛的時候,才不會搞錯資料型別,又 debug半天才發現是資料給錯!
註釋也可以放入指定型態的物件,就是接下來的 Interface。
interface 讓參數為物件時,有更明確的結構型態,而不是只是丟個參數表示為一個物件。
簡單的範例應該可以讓大家懂 interface 的概念。
interface Person {
firstName: string;
lastName: string;
}
function greeter(person: Person) {
return "Hello, " + person.firstName + " " + person.lastName;
}
var user = { firstName: "Tiger", lastName: "Liu" };
console.log(greeter(user));
以往在 ES5 的 JS 是沒辦法像 C++、JAVA那樣直接宣告類別的,JS開發者當然還是能透過一些技巧達到類似效果,但就比較麻煩也很不直觀。而 ES6 版本之後 JS 加入類別的語法糖,TS 中就能用相同的方式宣告類別,編譯成 JS後其實就是以前我們用來模擬類別的技巧啦!XD
class Student {
fullName: string;
constructor(public firstName, public middleInitial, public lastName) {
this.fullName = `${firstName} ${middleInitial} ${lastName}`;
}
}
interface Person {
firstName: string;
lastName: string;
}
function greeter(person : Person) {
return `Hello, ${person.firstName} ${person.lastName}`;
}
let user = new Student("Jane", "M.", "User");
console.log(greeter(user));
類別的靜態成員,他的屬性存在於類本身,而不是類的實例上
class Human {
static hands: number = 2;
static legs: number = 2;
}
有類別的概念,當然就會有繼承的概念
class Woman extends Human {
static gender: string = 'female';
}
interface 也可以用來強制類別符合約束
interface Shape {
area(): number;
}
class Circle implements Shape {
radius: number;
constructor(radius: number) {
this.radius = radius;
}
area(): number {
return this.radius * this.radius * 3.1415;
}
}
interface 也可以繼承其他的 interface
interface Shape {
area(): number;
}
interface Color {
RGB: string;
}
interface Thing extends Color, Shape {
}
多了 let ... of ...
的用法
let list = [4, 5, 6];
for (let i in list) {
console.log(i); // "0", "1", "2",
}
for (let i of list) {
console.log(i); // "4", "5", "6"
}
let ... of ...
的操作其實長這樣
let list = [4, 5, 6];
for (let _i = 0; _i < list.length; _i++) {
var num = list[_i];
console.log(num);
}
是疊代
lol
寫得滿詳細的,但篇幅稍嫌短了一點,謝謝你的用心!
謝謝分享,但是我有個疑問,下面的代碼
let user = new Student("Jane", "M.", "User");
console.log(greeter(user));
user可以傳入greeter函式裡是因為,Student的constructor裡的參數會自動成為屬性嗎?
所以greeter裡才找的到firstName和lastName嗎?
constructor
裡的參數會在 new
的時候初始化變數。意思是創立物件的時候,已經指派好值給物件的變數。
謝謝
這裡好像有筆誤?
let list = [4, 5, 6];
for (let _i = 0; _i < list.length; _i++) {
var let = list[_i]; // 是 var num = list[_i] ??
console.log(num);
}
對耶!! xD
Thanks!
對耶!! xD
Thanks!